package cn.vivi35.downloadprovider;

import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

public class DownloadHandler {

	private static final String TAG = "DownloadHandler";
	private final LinkedHashMap<Long, DownloadInfo> mDownloadsQueue = new LinkedHashMap<Long, DownloadInfo>();
	private final HashMap<Long, DownloadInfo> mDownloadsInProgress = new HashMap<Long, DownloadInfo>();
	private static final DownloadHandler mDownloadHandler = new DownloadHandler();
	/** mx threads allowed ,for muilti downloads , threads pools.. */
	private int mMaxConcurrentDownloadsAllowed = 3;


	public static DownloadHandler getInstance() {
		return mDownloadHandler;
	}


	synchronized void enqueueDownload(DownloadInfo info) {
		if (!mDownloadsQueue.containsKey(info.mId)) {
			if (Constants.LOGV) {
				Log.i(TAG, "enqueued download. id: " + info.mId + ", uri: " + info.mUri);
			}
			mDownloadsQueue.put(info.mId, info);
			startDownloadThread();
		}
	}


	private synchronized void startDownloadThread() {
		Iterator<Long> keys = mDownloadsQueue.keySet().iterator();
		ArrayList<Long> ids = new ArrayList<Long>();
		while (mDownloadsInProgress.size() < mMaxConcurrentDownloadsAllowed && keys.hasNext()) {
			Long id = keys.next();
			DownloadInfo info = mDownloadsQueue.get(id);
			// fix bug: 下载完了之后会重新下载，原因是mDownloadsQueue中的status没有更新，仍然是192（RUNNING），而不是200（SUCCESS)
			// TODO: 临时的办法，希望有更好的解决方法
			if (info.mStatus == Downloads.STATUS_RUNNING || info.mHasActiveThread
					|| info.mCurrentBytes > 0 && info.mCurrentBytes == info.mTotalBytes) {
				ids.add(id);
				continue;

			}

			// End fix bug
			info.startDownloadThread();
			ids.add(id);
			mDownloadsInProgress.put(id, mDownloadsQueue.get(id));
			if (Constants.LOGV) {
				Log.i(TAG, "started download for : " + id);
			}
		}
		for (Long id : ids) {
			mDownloadsQueue.remove(id);
		}
	}


	synchronized boolean hasDownloadInQueue(long id) {
		return mDownloadsQueue.containsKey(id) || mDownloadsInProgress.containsKey(id);
	}


	synchronized void dequeueDownload(long mId) {
		mDownloadsInProgress.remove(mId);
		mDownloadsQueue.remove(mId);
		startDownloadThread();
		if (mDownloadsInProgress.size() == 0 && mDownloadsQueue.size() == 0) {
			notifyAll();
		}
	}



	public int getMaxConcurrentDownloadsAllowed() {
		return mMaxConcurrentDownloadsAllowed;
	}



	public void setMaxConcurrentDownloadsAllowed(int maxConcurrentDownloadsAllowed) {
		this.mMaxConcurrentDownloadsAllowed = maxConcurrentDownloadsAllowed;
	}


	// right now this is only used by tests. but there is no reason why it can't be used
	// by any module using DownloadManager (TODO add API to DownloadManager.java)
	public synchronized void WaitUntilDownloadsTerminate() throws InterruptedException {
		if (mDownloadsInProgress.size() == 0 && mDownloadsQueue.size() == 0) {
			if (Constants.LOGVV) {
				Log.i(TAG, "nothing to wait on");
			}
			return;
		}
		if (Constants.LOGVV) {
			for (DownloadInfo info : mDownloadsInProgress.values()) {
				Log.i(TAG, "** progress: " + info.mId + ", " + info.mUri);
			}
			for (DownloadInfo info : mDownloadsQueue.values()) {
				Log.i(TAG, "** in Q: " + info.mId + ", " + info.mUri);
			}
		}
		if (Constants.LOGVV) {
			Log.i(TAG, "waiting for 5 sec");
		}
		// wait upto 5 sec
		wait(5 * 1000);
	}

	public boolean reachMaxConcurrentSize() {
		if(mDownloadsInProgress.size() < mMaxConcurrentDownloadsAllowed) {
			return false;
		} else {
			return true;
		}
	}
}
